package com.pc.scrs.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.pc.scrs.bean.bo.RecommendResult;
import com.pc.scrs.bean.bo.UserM;
import com.pc.scrs.bean.po.Course;
import com.pc.scrs.bean.po.Student;
import com.pc.scrs.bean.po.Users;
import com.pc.scrs.bean.vo.listVo.RecommendListVo;
import com.pc.scrs.bean.vo.pageInfo.RecommendListVoPageInfo;
import com.pc.scrs.dao.CourseDao;
import com.pc.scrs.dao.StudentDao;
import com.pc.scrs.dao.UsersDao;
import com.pc.scrs.service.IRecommendService;
import com.pc.scrs.utils.JwtUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

@Service
@Transactional
public class RecommendService implements IRecommendService {

    @Resource
    private UsersDao usersDao;

    @Resource
    private StudentDao studentDao;

    @Resource
    private CourseDao courseDao;

    @Override
    public RecommendListVoPageInfo recommendList(String token, Integer pageNum, Integer pageSize) {

        PageHelper.startPage(pageNum, pageSize);

        //获取当前登录用户的选课列表
        UserM userM = getCurrentUserMSelect(token);

        List<Course> recommendCourseList;

        //若当前用户选课列表为空则默认随机推荐
        if(userM.getSelect().size()<=0){
            recommendCourseList = randomCourseList();
        }else {
            //获取除当前登录用户外的其他所有用户列表
            List<UserM> otherUserMList = getOtherUserM(token);

            //获取与当前登录用户相关的用户列表
            List<UserM> userMS = searchUserM(userM, otherUserMList);

            for(int i = 0 ; i < userMS.size() ; i++){
                //用杰卡德相似系数求相似度--杰卡德系数 = 交集/并集,并赋值
                userMS.get(i).setSeem(compare(userM,userMS.get(i)));
            }
            //获取推荐结果
            Map<String, Double> recommend = recommend(userM, userMS);
            System.out.println(recommend);
            //封装并排序
            recommendCourseList = getRecommendCourseList(recommend);
        }


        List<RecommendListVo> recommendListVoList = new ArrayList<>();
        PageInfo<Course> coursePageInfo = new PageInfo<>(recommendCourseList);

        for (Course course : recommendCourseList) {
            RecommendListVo recommendListVo = new RecommendListVo();
            recommendListVo.setId(course.getId());
            recommendListVo.setCover(course.getCover());
            recommendListVo.setTitle(course.getTitle());
            recommendListVo.setLessonNum(course.getLessonNum());
            recommendListVo.setSubjectName(course.getSubject().getTitle());
            recommendListVoList.add(recommendListVo);
        }
        RecommendListVoPageInfo recommendListVoPageInfo = new RecommendListVoPageInfo();
        recommendListVoPageInfo.setRecommendListVoList(recommendListVoList);
        recommendListVoPageInfo.setPageNum(coursePageInfo.getPageNum());
        recommendListVoPageInfo.setPageSize(coursePageInfo.getPageSize());
        recommendListVoPageInfo.setPages(coursePageInfo.getPages());
        recommendListVoPageInfo.setTotal(coursePageInfo.getTotal());
        return recommendListVoPageInfo;

    }

    /**
     * 当前用户若选课列表为空，则随机推荐选修课
     * @return
     */
    public List<Course> randomCourseList(){
        Random random = new Random();
        List<Integer> ids = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            ids.add(random.nextInt(courseDao.getSelectList().size()));
        }
        List<Course> randomCourseList = courseDao.randomCourseList(ids);
        return randomCourseList;
    }

    /**
     * 获取当前登录用户的选课列表
     * @param token
     * @return
     */
    public UserM getCurrentUserMSelect(String token){
        //根据controller层获取token并解析出userid
        String username = JwtUtils.getUserNameFormJwt(token);
        Users users = usersDao.userInfo(username);
        Student student = studentDao.queryStudentByUserId(users.getId());
        List<Integer> courseIdList = studentDao.queryCourseByStudentId(student.getId());
        UserM userM = new UserM();
        List<String> subjectList = new ArrayList<>();
        if(courseIdList!=null){
            for (Integer courseId : courseIdList) {
                Course course = courseDao.querySubjectTitleByCourseId(courseId);
                if(course!=null){
                    if(!subjectList.contains(course.getSubject().getTitle())){
                        subjectList.add(course.getSubject().getTitle());
                    }
                }
            }
        }
        userM.setSelect(subjectList);
        return userM;
    }

    /**
     * 获取其他用户列表
     * @param token
     * @return
     */
    public List<UserM> getOtherUserM(String token){
        //根据controller层获取token并解析出userid
        String username = JwtUtils.getUserNameFormJwt(token);
        Users users = usersDao.userInfo(username);
        Student student = studentDao.queryStudentByUserId(users.getId());
        List<Student> studentList = studentDao.queryAllStudent();
        //排除当前登录用户
        if(studentList.contains(student)){
            studentList.remove(student);
        }
        List<UserM> userMList = new ArrayList<>();
        for (Student stu : studentList) {
            List<Integer> everyStuCourseIdList = studentDao.queryCourseByStudentId(stu.getId());
            if(everyStuCourseIdList!=null){
                UserM userM1 = new UserM();
                List<String> everyStuSubjectList = new ArrayList<>();
                for (Integer cId : everyStuCourseIdList) {
                    Course course = courseDao.querySubjectTitleByCourseId(cId);
                    if(course!=null){
                        if(!everyStuSubjectList.contains(course.getSubject().getTitle())){
                            everyStuSubjectList.add(course.getSubject().getTitle());
                        }
                    }
                }
                userM1.setSelect(everyStuSubjectList);
                userMList.add(userM1);
            }
        };
        return userMList;
    }

    /**
     * 将结果封装转化为课程列表并按照推荐度降序排序
     * @param recommend
     * @return
     */
    public List<Course> getRecommendCourseList(Map<String, Double> recommend){
        List<RecommendResult> recommendResultList = new ArrayList<>();
        Iterator<Map.Entry<String,Double>> iterator = recommend.entrySet().iterator();
        while (iterator.hasNext()){
            RecommendResult recommendResult = new RecommendResult();
            Map.Entry<String,Double> entry = iterator.next();
            recommendResult.setSubjectTitle(entry.getKey());
            recommendResult.setRecommendDegree(entry.getValue());
            recommendResultList.add(recommendResult);
        }
        Collections.sort(recommendResultList);
        System.out.println(recommendResultList);
        Random random = new Random();
        List<Course> recommendCourseList = new ArrayList<>();
        for (RecommendResult recommendResult : recommendResultList) {
            List<Course> courses = courseDao.randomQueryCourseBySubjectTitle(recommendResult.getSubjectTitle());
            Course course = courses.get(random.nextInt(courses.size()));
            recommendCourseList.add(course);
        }
        return recommendCourseList;
    }

    /**
     *
     * @param userM  当前登录用户
     * @param list   全部用户
     * @return 与当前登录用户相关的用户
     */
    public List<UserM> searchUserM(UserM userM,List<UserM> list){
        List<String> select = new ArrayList<>();//存放当前登录用户所选择课程的科目类型
        List<UserM> listU = new ArrayList<>();//存放与当前登录用户相关的用户
        for(int i = 0 ; i < userM.getSelect().size() ; i++){
            select.add(userM.getSelect().get(i));
        }
        for(int i = 0 ; i < list.size() ; i++){
            for(int j = 0 ; j < list.get(i).getSelect().size() ; j++){
                if(select.contains(list.get(i).getSelect().get(j))){
                    listU.add(list.get(i));
                    break;
                }else{
                    continue;
                }
            }
        }
        return listU;
    }

    /**
     *
     * @param userM1 当前登录用户
     * @param userM2 要进行相似度比较的用户
     * @return 相似度
     *      //比较两个集合，相同的即放在union，又放在intersection
     *     //不同的，放在union
     *     //用杰卡德相似系数求相似度--杰卡德系数 = 交集/并集
     */
    public double compare(UserM userM1,UserM userM2){
        //并集
        List<String> union = new ArrayList<>();
        //交集
        List<String> intersection = new ArrayList<>();
        List<String> select1 = userM1.getSelect();
        List<String> select2 = userM2.getSelect();

        //将userM1的select先放入并集
        for(int i = 0 ; i < select1.size() ; i++){
            union.add(select1.get(i));
        }
        //将select2与并集进行对比
        for(int i = 0 ; i < select2.size() ; i++){
            if(union.contains(select2.get(i))){
                //如果并集中存在，加入到交集中
                intersection.add(select2.get(i));
            }else{
                //并集中不存在，加到并集中
                union.add(select2.get(i));
            }
        }
        //相似度
        double likes = (double)intersection.size()/union.size();
        return likes;
    }

    /**
     *
     * @param userM 当前用户
     * @param list 与当前用户相关的用户
     * @return 对当前用户的课程的推荐度
     */
    public Map<String,Double> recommend(UserM userM, List<UserM> list){
        List<String> recommends = new ArrayList<>();
        Map<String,Double> map = new HashMap<>();
            for(int i = 0 ; i < list.get(0).getSelect().size() ; i++){
                recommends.add(list.get(0).getSelect().get(i));
                map.put(list.get(0).getSelect().get(i),list.get(0).getSeem());
            }
            for(int j = 1 ; j < list.size() ; j++){
            for(int i = 0 ; i < list.get(j).getSelect().size() ; i++){
                //如果recommends里面存在，即有交集
                if(recommends.contains(list.get(j).getSelect().get(i))){
//                    System.out.println(map.get(list.get(j).getSelect().get(i)));
                    //如果有，修改值
                    map.replace(list.get(j).getSelect().get(i),map.get(list.get(j).getSelect().get(i))+list.get(j).getSeem());
//                    System.out.println(map.get(list.get(j).getSelect().get(i)));
                }else{
                    //recommends中不存在
                    map.put(list.get(j).getSelect().get(i),list.get(j).getSeem());
                }
            }
        }
        return map;
    }
}
